﻿/*======================================================================
== Copyright : BlueCurve (c)
== Licence   : Gnu/GPL v2.x
== Author    : Teddy Albina
== Email     : bluecurveteam@gmail.com
== Web site  : http://www.codeplex.com/BlueCurve
========================================================================*/
using System;

namespace BlueCurve.Common.Share
{
    /// <summary>
    /// Contient les méthodes permettant d'effectuer des connexions aux ressources réseau.
    /// </summary>
    public class NetworkShare
    {
        #region Nested

        /// <summary>
        /// Définit les modes d'affichage de l'invite de saisie utilisateur.
        /// </summary>
        public enum PromptMode
        {
            /// <summary>
            /// Jamais.
            /// </summary>
            None,
            /// <summary>
            /// Toujours demander la saisie par l'utilisateur.
            /// </summary>
            Always,
            /// <summary>
            /// Seulement si l'essai avec le contexte utilisateur courant à échouer.
            /// </summary>
            OnlyIfNeeded
        }

        #endregion Nested

        #region Constructeurs

        /// <summary>
        /// Initialise une nouvelle instance de <see cref="NetworkShare"/>.
        /// </summary>
        /// <param name="remoteName"></param>
        private NetworkShare(string remoteName)
        {
            this._remoteName = remoteName;
        }

        #endregion Constructeurs

        #region Champs

        /// <summary>
        /// Nom distant
        /// </summary>
        private string _remoteName;

        #endregion Champs

        #region Méthodes de connexion de disques

        /// <summary>
        /// Effectue la connexion au partage réseau.
        /// </summary>
        /// <param name="remoteName">Chemin d'accès au partage. (ex: "\\monserveur\mon partage")</param>
        /// <param name="user">Nom d'utilisateur.</param>
        /// <param name="pass">Mot de passe de l'utilisateur.</param>
        /// <param name="flags">Valeur ou combinaison de valeurs de <see cref="NativeMethods.WNetAddConnectionFlags"/>.</param>
        /// <param name="hwndOwner">Handle de la fenêtre à spécifier en propriétaire des éventuelles boites de dialogue.</param>
        /// <returns>Instance de <see cref="NetworkShare"/> si réussite de la connexion, sinon <c>null</c>.</returns>
        private static NetworkShare ConnectDiskInternal(string remoteName, string user, string pass, NativeMethods.WNetAddConnectionFlags flags, IntPtr hwndOwner)
        {
            NetworkShare share = null;
            try
            {
                uint ret;
                NETRESOURCE netres = new NETRESOURCE();
                netres.dwType = NETRESOURCE.Type.RESOURCETYPE_DISK;
                netres.lpRemoteName = remoteName;

                ret = NativeMethods.WNetAddConnection3(
                    hwndOwner,
                    ref netres,
                    pass,
                    user,
                    flags
                    );

                if (ret == NativeMethods.NO_ERROR)
                    share = new NetworkShare(remoteName);
                else
                    share = null;
            }
            catch
            {
                share = null;
            }
            return share;
        }

        /// <overloads>Effectue la connexion au partage.</overloads>
        /// <summary>
        /// Tente la connexion dans le contexte de l'utilisateur courant, et affiche la demande de saisie en cas d'échec.
        /// </summary>
        /// <param name="remoteName">Chemin d'accès au partage. (ex: "\\monserveur\mon partage")</param>
        /// <returns>Instance de <see cref="NetworkShare"/> si réussite de la connexion, sinon <c>null</c>.</returns>
        public static NetworkShare ConnectDisk(string remoteName)
        {
            return ConnectDisk(remoteName, PromptMode.OnlyIfNeeded);
        }

        /// <summary>
        /// Tente la connexion dans le contexte de l'utilisateur courant, et affiche la demande de saisie en cas d'échec.
        /// </summary>
        /// <param name="remoteName">Chemin d'accès au partage. (ex: "\\monserveur\mon partage")</param>
        /// <param name="hwndOwner">Handle de la fenêtre à spécifier en propriétaire des éventuelles boites de dialogue.</param>
        /// <returns>Instance de <see cref="NetworkShare"/> si réussite de la connexion, sinon <c>null</c>.</returns>
        public static NetworkShare ConnectDisk(string remoteName, IntPtr hwndOwner)
        {
            return ConnectDisk(remoteName, PromptMode.OnlyIfNeeded, hwndOwner);
        }

        /// <summary>
        /// Tente la connexion dans le contexte de l'utilisateur courant. 
        /// L'affichage éventuel de la demande de saisie est fonction de la valeur de <c>mode</c>.
        /// </summary>
        /// <param name="remoteName">Chemin d'accès au partage. (ex: "\\monserveur\mon partage")</param>
        /// <param name="mode">Mode d'affichage de l'invite de saisie utilisateur.</param>
        /// <returns>Instance de <see cref="NetworkShare"/> si réussite de la connexion, sinon <c>null</c>.</returns>
        public static NetworkShare ConnectDisk(string remoteName, PromptMode mode)
        {
            return ConnectDisk(remoteName, mode, IntPtr.Zero);
        }

        /// <summary>
        /// Tente la connexion dans le contexte de l'utilisateur courant. 
        /// L'affichage éventuel de la demande de saisie est fonction de la valeur de <c>mode</c>. 
        /// </summary>
        /// <param name="remoteName">Chemin d'accès au partage. (ex: "\\monserveur\mon partage")</param>
        /// <param name="mode">Mode d'affichage de l'invite de saisie utilisateur.</param>
        /// <param name="hwndOwner">Handle de la fenêtre à spécifier en propriétaire des éventuelles boites de dialogue.</param>
        /// <returns>Instance de <see cref="NetworkShare"/> si réussite de la connexion, sinon <c>null</c>.</returns>
        public static NetworkShare ConnectDisk(string remoteName, PromptMode mode, IntPtr hwndOwner)
        {
            NativeMethods.WNetAddConnectionFlags flags = GetWNetAddConnectionFlagsFromPromptMode(mode);
            return ConnectDiskInternal(remoteName, null, null, flags, hwndOwner);
        }

        /// <summary>
        /// Tente la connexion avec le nom d'utilisateur et le mot de passe fournis.
        /// </summary>
        /// <param name="remoteName">Chemin d'accès au partage. (ex: "\\monserveur\mon partage")</param>
        /// <param name="user">Nom d'utilisateur.</param>
        /// <param name="pass">Mot de passe de l'utilisateur.</param>
        /// <returns>Instance de <see cref="NetworkShare"/> si réussite de la connexion, sinon <c>null</c>.</returns>
        public static NetworkShare ConnectDisk(string remoteName, string user, string pass)
        {
            return ConnectDisk(remoteName, user, pass, PromptMode.OnlyIfNeeded);
        }

        /// <summary>
        /// Tente la connexion avec le nom d'utilisateur et le mot de passe fournis.
        /// </summary>
        /// <param name="remoteName">Chemin d'accès au partage. (ex: "\\monserveur\mon partage")</param>
        /// <param name="user">Nom d'utilisateur.</param>
        /// <param name="pass">Mot de passe de l'utilisateur.</param>
        /// <param name="hwndOwner">Handle de la fenêtre à spécifier en propriétaire des éventuelles boites de dialogue.</param>
        /// <returns>Instance de <see cref="NetworkShare"/> si réussite de la connexion, sinon <c>null</c>.</returns>
        public static NetworkShare ConnectDisk(string remoteName, string user, string pass, IntPtr hwndOwner)
        {
            return ConnectDisk(remoteName, user, pass, PromptMode.OnlyIfNeeded, hwndOwner);
        }

        /// <summary>
        /// Tente la connexion avec le nom d'utilisateur et le mot de passe fournis.
        /// L'affichage éventuel de la demande de saisie est fonction de la valeur de <c>mode</c>. 
        /// </summary>
        /// <param name="remoteName">Chemin d'accès au partage. (ex: "\\monserveur\mon partage")</param>
        /// <param name="user">Nom d'utilisateur.</param>
        /// <param name="pass">Mot de passe de l'utilisateur.</param>
        /// <param name="mode">Mode d'affichage de l'invite de saisie utilisateur.</param>
        /// <returns>Instance de <see cref="NetworkShare"/> si réussite de la connexion, sinon <c>null</c>.</returns>
        public static NetworkShare ConnectDisk(string remoteName, string user, string pass, PromptMode mode)
        {
            return ConnectDisk(remoteName, user, pass, mode, IntPtr.Zero);
        }

        /// <summary>
        /// Tente la connexion avec le nom d'utilisateur et le mot de passe fournis.
        /// L'affichage éventuel de la demande de saisie est fonction de la valeur de <c>mode</c>. 
        /// </summary>
        /// <param name="remoteName">Chemin d'accès au partage. (ex: "\\monserveur\mon partage")</param>
        /// <param name="user">Nom d'utilisateur.</param>
        /// <param name="pass">Mot de passe de l'utilisateur.</param>
        /// <param name="mode">Mode d'affichage de l'invite de saisie utilisateur.</param>
        /// <param name="hwndOwner">Handle de la fenêtre à spécifier en propriétaire des éventuelles boites de dialogue.</param>
        /// <returns>Instance de <see cref="NetworkShare"/> si réussite de la connexion, sinon <c>null</c>.</returns>
        public static NetworkShare ConnectDisk(string remoteName, string user, string pass, PromptMode mode, IntPtr hwndOwner)
        {
            NativeMethods.WNetAddConnectionFlags flags = GetWNetAddConnectionFlagsFromPromptMode(mode);
            return ConnectDiskInternal(remoteName, user, pass, flags, hwndOwner);
        }

        #endregion Méthodes de connexion de disques

        #region Méthodes de déconnexion

        /// <overloads>Effectue la déconnexion de la ressource. (Equivalent à "net use /delete")</overloads>
        /// <summary>
        /// Effectue la déconnexion de la ressource, sans la forcer. (Equivalent à "net use /delete")
        /// </summary>
        public void Disconnect()
        {
            this.Disconnect(false);
        }

        /// <summary>
        /// Effectue la déconnexion de la ressource. (Equivalent à "net use /delete") 
        /// Le forçage de la déconnexion est fonction de la valeur de <c>force</c>.
        /// </summary>
        /// <param name="force">Détermine si il faut on non forcer la déconnexion.</param>
        public void Disconnect(bool force)
        {
            try
            {
                NativeMethods.WNetCancelConnection2(this._remoteName, 0, force);
            }
            catch
            {
            }
        }

        #endregion Méthodes de déconnexion

        #region Méthodes utilitaires

        /// <summary>
        /// Permet d'initiliser les flags à partir d'une valeur de PromptMode.
        /// </summary>
        /// <param name="mode"></param>
        /// <returns></returns>
        private static NativeMethods.WNetAddConnectionFlags GetWNetAddConnectionFlagsFromPromptMode(PromptMode mode)
        {
            NativeMethods.WNetAddConnectionFlags flags;

            switch (mode)
            {
                case PromptMode.OnlyIfNeeded:
                    flags = NativeMethods.WNetAddConnectionFlags.CONNECT_INTERACTIVE;
                    break;
                case PromptMode.Always:
                    flags = NativeMethods.WNetAddConnectionFlags.CONNECT_INTERACTIVE | NativeMethods.WNetAddConnectionFlags.CONNECT_PROMPT;
                    break;
                case PromptMode.None:
                default:
                    flags = 0;
                    break;
            }
            return flags;
        }

        #endregion Méthodes utilitaires
    }
}
